package tech.darkblue.rpcui.menu.run;

import java.io.File;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Dialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.springframework.util.CollectionUtils;

import tech.darkblue.rpcui.attribute.ParameterAttribute;
import tech.darkblue.rpcui.config.Configurations;
import tech.darkblue.rpcui.util.SwtUtils;
import tech.darkblue.rpcui.util.XmlUtils;

public class RunAsDialog extends Dialog {

    protected Object result;
    protected Shell shellRunAsConfig;

    private Combo cmbJarName;
    private Combo cmbInterface;
    private Combo cmbMethod;
    private Button btnOK;

    /**
     * Create the dialog.
     * @param parent
     * @param style
     */
    public RunAsDialog(Shell parent, int style) {
        super(parent, style | SwtUtils.DIALOG_RESIZE);
    }

    /**
     * Open the dialog.
     * @return the result
     * @throws Exception
     */
    public Object open() throws Exception {
        createContents();
        SwtUtils.centerDialog(shellRunAsConfig, getParent());
        shellRunAsConfig.open();
        shellRunAsConfig.layout();
        Display display = getParent().getDisplay();
        while (!shellRunAsConfig.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
        return result;
    }

    /**
     * Create contents of the dialog.
     * @throws Exception
     */
    private void createContents() throws Exception {
        shellRunAsConfig = new Shell(getParent(), getStyle());
        shellRunAsConfig.setImages(Configurations.DEFAULT_ICON_IMAGES);
        shellRunAsConfig.setSize(450, 184);
        shellRunAsConfig.setText("Run As Configuration");
        GridLayout gl_shellRunAsConfig = new GridLayout(1, false);
        gl_shellRunAsConfig.marginWidth = 0;
        gl_shellRunAsConfig.marginHeight = 0;
        shellRunAsConfig.setLayout(gl_shellRunAsConfig);

        Composite compRunConfig = new Composite(shellRunAsConfig, SWT.NONE);
        compRunConfig.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
        compRunConfig.setLayout(new GridLayout(2, false));

        Label lblJarName = new Label(compRunConfig, SWT.NONE);
        lblJarName.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
        lblJarName.setText("Jar Name :");

        cmbJarName = new Combo(compRunConfig, SWT.READ_ONLY);
        cmbJarName.addModifyListener(new ModifyListener() {
            public void modifyText(ModifyEvent arg0) {
                checkNextButtonEnabled();
                if (cmbInterface != null) {
                    cmbInterface.removeAll();
                    if (StringUtils.isNotEmpty(cmbJarName.getText())) {
                        try {
                            setComboItemByXPath(cmbInterface,
                                    "//attribute[@name=\"" + cmbJarName.getText() + "\"]/interfaces/interface");
                        } catch (DocumentException e) {
                            e.printStackTrace();
                        }
                    }
                }
                if (cmbMethod != null) {
                    cmbMethod.removeAll();
                }
            }
        });
        cmbJarName.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
        setComboItemByXPath(cmbJarName, "//attribute");

        Label lblInterface = new Label(compRunConfig, SWT.NONE);
        lblInterface.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
        lblInterface.setText("Interface :");

        cmbInterface = new Combo(compRunConfig, SWT.READ_ONLY);
        cmbInterface.addModifyListener(new ModifyListener() {
            public void modifyText(ModifyEvent arg0) {
                checkNextButtonEnabled();
                if (cmbMethod != null) {
                    cmbMethod.removeAll();
                    if (StringUtils.isNotEmpty(cmbInterface.getText())) {
                        try {
                            setComboItemByXPath(cmbMethod,
                                    "//attribute[@name=\"" + cmbJarName.getText() + "\"]" +
                                    "/interfaces/interface[@name=\"" + cmbInterface.getText() + "\"]/methods/method", true);
                        } catch (DocumentException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        });
        cmbInterface.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));

        Label lblMethod = new Label(compRunConfig, SWT.NONE);
        lblMethod.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
        lblMethod.setText("Method :");

        cmbMethod = new Combo(compRunConfig, SWT.READ_ONLY);
        cmbMethod.addModifyListener(new ModifyListener() {
            public void modifyText(ModifyEvent arg0) {
                checkNextButtonEnabled();
            }
        });
        cmbMethod.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));

        Composite composite = new Composite(shellRunAsConfig, SWT.NONE);
        composite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
        composite.setLayout(new GridLayout(1, false));

        Label label = new Label(composite, SWT.SEPARATOR | SWT.HORIZONTAL);
        label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1));

        Composite compAction = new Composite(composite, SWT.NONE);
        compAction.setLayoutData(new GridData(SWT.RIGHT, SWT.BOTTOM, true, false, 1, 1));

        btnOK = new Button(compAction, SWT.NONE);
        btnOK.setEnabled(false);
        btnOK.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                ParameterAttribute paramAttribute = (ParameterAttribute) cmbMethod.getData(
                        String.valueOf(cmbMethod.getSelectionIndex()));
                paramAttribute.setJarName(cmbJarName.getText());
                paramAttribute.setInterfaceName(cmbInterface.getText());
                shellRunAsConfig.close();
                shellRunAsConfig.dispose();
                try {
                    RunConfigDialog dlgRunConfiguration = new RunConfigDialog(getParent(),
                            SwtUtils.DIALOG_DEFAULT_STYLE, false);
                    dlgRunConfiguration.setParameterAttribute(paramAttribute);
                    dlgRunConfiguration.open();
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        });
        btnOK.setBounds(0, 1, 80, 27);
        btnOK.setText("OK");

        Button btnClose = new Button(compAction, SWT.NONE);
        btnClose.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                shellRunAsConfig.close();
                shellRunAsConfig.dispose();
            }
        });
        btnClose.setBounds(86, 1, 80, 27);
        btnClose.setText("Close");

    }

    private void checkNextButtonEnabled() {
        if (btnOK != null) {
            if (StringUtils.isNotEmpty(cmbJarName.getText())
                    && StringUtils.isNotEmpty(cmbInterface.getText()) && StringUtils.isNotEmpty(cmbMethod.getText())) {
                btnOK.setEnabled(true);
            } else {
                btnOK.setEnabled(false);
            }
        }
    }

    private void setComboItemByXPath(Combo combo, String xpath) throws DocumentException {
        setComboItemByXPath(combo, xpath, false);
    }

    private void setComboItemByXPath(Combo combo, String xpath, boolean parseArgumentNode) throws DocumentException {
        Document xmlDoc = XmlUtils.getDocument(new File(Configurations.FILE_ATTRIBUTES));
        List<?> selectedNodes = xmlDoc.selectNodes(xpath);
        if (!CollectionUtils.isEmpty(selectedNodes)) {
            String[] comboItems = new String[selectedNodes.size()];
            for (int i = 0; i < selectedNodes.size(); i++) {
                if (parseArgumentNode) {
                    ParameterAttribute paramAttribute = new ParameterAttribute();
                    Element selectedNode = (Element)selectedNodes.get(i);
                    Element argumentsNode = selectedNode.element("arguments");
                    paramAttribute.setMethodName(selectedNode.attributeValue("name"));

                    if (argumentsNode == null) {
                        comboItems[i] = selectedNode.attributeValue("name") + "()";
                    } else {
                        List<?> argumentNodes = argumentsNode.elements();
                        String[] parameterTypes = new String[argumentNodes.size()];
                        for (int j = 0; j < argumentNodes.size(); j++) {
                            parameterTypes[j] = ((Element) argumentNodes.get(j)).attributeValue("type");
                        }
                        comboItems[i] = (selectedNode.attributeValue("name") + "(" + StringUtils.join(parameterTypes,
                                ", ") + ")");
                        paramAttribute.setParameterTypes(parameterTypes);
                    }
                    combo.setData(String.valueOf(i), paramAttribute);
                } else {
                    comboItems[i] = ((Element)selectedNodes.get(i)).attributeValue("name");
                }
            }
            combo.setItems(comboItems);
        }
    }

}
